#pragma once

#include <pthread.h>
#include <queue>
#include <string>

using namespace std;



//template<class T>
// class BlockQueue
// {
// public:
//     BlockQueue(description *info, pthread_cond_t *p_cond, pthread_cond_t *c_cond,
//                pthread_mutex_t *mutex, queue<int> *bq, int max = 5)
//             : _info(info)
//             , _p_cond(p_cond)
//             , _c_cond(c_cond)
//             , _mutex(mutex)
//             , _bq(bq)
//             , _max(max)
//     {
//         pthread_cond_init(_p_cond, nullptr);
//         pthread_cond_init(_c_cond, nullptr);
//         pthread_mutex_init(_mutex, nullptr);
//     }

//     void push(int val)
//     {
//         pthread_mutex_lock(_mutex);
//         while (_bq->size() >= _max)
//         {
//             pthread_cond_wait(_p_cond, _mutex);
//         }
//         _bq->push(val);
//         pthread_cond_signal(_c_cond);
//         pthread_mutex_unlock(_mutex);
//     }

//     int pop()
//     {
//         pthread_mutex_lock(_mutex);
//         if (_bq->size() <= 0)
//         {
//             pthread_cond_wait(_c_cond, _mutex);
//         }
//         int ret = _bq->front();
//         _bq->pop();
//         pthread_cond_signal(_p_cond);
//         pthread_mutex_unlock(_mutex);
//         return ret;
//     }

//     ~BlockQueue()
//     {
//         pthread_cond_destroy(_p_cond);
//         pthread_cond_destroy(_c_cond);
//         pthread_mutex_destroy(_mutex);
//     }

// private:
//     description *_info;

//     pthread_cond_t *_p_cond;
//     pthread_cond_t *_c_cond;
//     pthread_mutex_t *_mutex;

//     queue<int> *_bq;
//     int _max;
// };


struct description
{
    pthread_t _pid;
    string _name;
};

// class BlockQueue
// {
// public:
//     BlockQueue(int max = 5)
//         :_max(max)
//     {
//         pthread_cond_init(&_p_cond, nullptr);
//         pthread_cond_init(&_c_cond, nullptr);
//         pthread_mutex_init(&_mutex, nullptr);
//     }

//     void push(int val)
//     {
//         pthread_mutex_lock(&_mutex);
//         while (_bq.size() >= _max)
//         {
//             pthread_cond_wait(&_p_cond, &_mutex);
//         }
//         _bq.push(val);
//         pthread_cond_signal(&_c_cond);
//         pthread_mutex_unlock(&_mutex);
//     }

//     int pop()
//     {
//         pthread_mutex_lock(&_mutex);
//         if (_bq.size() <= 0)
//         {
//             pthread_cond_wait(&_c_cond, &_mutex);
//         }
//         int ret = _bq.front();
//         _bq.pop();
//         pthread_cond_signal(&_p_cond);
//         pthread_mutex_unlock(&_mutex);
//         return ret;
//     }

//     ~BlockQueue()
//     {
//         pthread_cond_destroy(&_p_cond);
//         pthread_cond_destroy(&_c_cond);
//         pthread_mutex_destroy(&_mutex);
//     }

// private:
//     pthread_cond_t _p_cond;
//     pthread_cond_t _c_cond;
//     pthread_mutex_t _mutex;

//     queue<int> _bq;
//     int _max;
// };




template<class T>
class BlockQueue
{
public:
    BlockQueue(int max = 5)
        :_max(max)
    {
        pthread_cond_init(&_p_cond, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_mutex_init(&_mutex, nullptr);
    }

    void push(T val)
    {
        pthread_mutex_lock(&_mutex);
        while (_bq.size() >= _max)
        {
            pthread_cond_wait(&_p_cond, &_mutex);
        }
        _bq.push(val);
        pthread_cond_signal(&_c_cond);
        pthread_mutex_unlock(&_mutex);
    }

    T pop()
    {
        pthread_mutex_lock(&_mutex);
        if (_bq.size() <= 0)
        {
            pthread_cond_wait(&_c_cond, &_mutex);
        }
        T ret = _bq.front();
        _bq.pop();
        pthread_cond_signal(&_p_cond);
        pthread_mutex_unlock(&_mutex);
        return ret;
    }

    ~BlockQueue()
    {
        pthread_cond_destroy(&_p_cond);
        pthread_cond_destroy(&_c_cond);
        pthread_mutex_destroy(&_mutex);
    }

private:
    pthread_cond_t _p_cond;
    pthread_cond_t _c_cond;
    pthread_mutex_t _mutex;

    queue<T> _bq;
    int _max;
};
